package me.leoray.leilog;

import android.content.Context;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 设置
 * Created by leoraylei on 16/8/27.
 */
public class Settings {
    private static final String ROOT_TAG = "LeoLog";

    /**
     * 代理Settings,代理除rootTag和saveFile以外的配置
     */
    private Settings proxy;

    /**
     * 1. 根Tag
     */
    private String rootTag;

    /**
     * 2. 日志装饰器
     */
    private LogDecoration logDecoration;
    //不同的日志级别可以设置不同的装饰器
    private Map<Integer, LogDecoration> mLogDecorationMap;
    /**
     * 3. 代理
     */
    private LogProxy logProxy;
    /**
     * 4. 日志输出器
     */
    private List<PipeLine> pipeLineList;
    //内置的两个日志输出器
    private FilePipeLine filePipeLine; //文件输出
    private ConsolePipeLine consolePipeLine; //控制台输出

    /**
     * 共享指定的配置,如果当前配置没有设置则共享代理配置.一旦自己做了相关配置则不再使用代理配置
     *
     * @param proxy
     * @return
     */
    public static Settings share(Settings proxy) {
        Settings result = new Settings(proxy);
        return result;
    }

    /**
     * 新建一个配置
     *
     * @param rootTag
     * @return
     */
    public static Settings of(String rootTag) {
        Settings settings = new Settings();
        settings.rootTag = rootTag;
        return settings;
    }

    public Settings() {
        this(null);
    }

    public Settings(Settings proxy) {
        if (proxy == null) {
            //默认配置
            this.rootTag = ROOT_TAG;
            this.logDecoration = new NormalLogDecoration();
            this.consolePipeLine = new ConsolePipeLine();
            this.pipeLineList = new ArrayList<>();
            this.pipeLineList.add(consolePipeLine);
        } else {
            //依赖代理
            this.proxy = proxy;
        }
    }

    /**
     * 拿到文件存储位置
     *
     * @return
     */
    String logDir() {
        if (filePipeLine != null) { //本身已经设置
            return filePipeLine.logDir();
        } else if (proxy != null) {
            return proxy.filePipeLine.logDir();
        } else {
            throw new RuntimeException("init Settings error:logDir error");
        }
    }

    int fileSaveLevel() {
        if (filePipeLine != null) {
            return filePipeLine.level;
        } else if (proxy != null) {
            return proxy.filePipeLine.level;
        } else {
            throw new RuntimeException("init Settings error:fileSaveLevel error");
        }
    }

    /*--------------------------------基本配置---START-----------------------------*/

    /**
     * 设置控制台输出日志的级别
     *
     * @param level
     * @return
     */
    public Settings logLevel(int level) {
        if (this.consolePipeLine == null) {
            this.consolePipeLine = new ConsolePipeLine();
        }
        return addPipeLine(consolePipeLine.level(level));
    }


    public Settings rootTag(String tag) {
        this.rootTag = tag;
        return this;
    }


    String rootTag() {
        if (this.rootTag == null && proxy != null) {
            return proxy.rootTag();
        }
        return rootTag;
    }
    /*--------------------------------基本配置---START-----------------------------*/



    /*--------------------------------LogProxy配置---START-----------------------------*/


    /**
     * 设置日志代理,所有的{@link PipeLine}都会失效,但是{@link LogDecoration}不会失效
     * 每个{@link AbstractPipeLine}都可以设置自己的代理
     *
     * @param logProxy
     */
    public void setProxy(LogProxy logProxy) {
        this.logProxy = logProxy;
    }

    LogProxy getLogProxy() {
        if (this.logProxy == null && this.proxy != null) {
            return proxy.getLogProxy();
        }
        return logProxy;
    }

    /**
     * 设置控制台日志代理
     * 等价于调用{@link ConsolePipeLine#setLogProxy(LogProxy)}
     *
     * @param logProxy
     */
    public ConsolePipeLine setProxy4ConsolePipeline(LogProxy logProxy) {
        if (consolePipeLine == null) { //如果为null,可以设置一波
            logLevel(Log.DEBUG);
        }
        return consolePipeLine.setLogProxy(logProxy);
    }

    public FilePipeLine setProxy4FilePipeline(LogProxy logProxy) {
        if (filePipeLine == null) { //如果为null,可以设置一波
            openLogSave();
        }
        return filePipeLine.setLogProxy(logProxy);
    }
    /*--------------------------------LogProxy配置---END-----------------------------*/


    /*--------------------------------LogDecoration配置----START-----------------------*/
    //这里内置的三种日志装饰器
    public NormalLogDecoration logSimple() {
        final NormalLogDecoration normalLogDecoration = new NormalLogDecoration();
        this.logDecoration = normalLogDecoration;
        return normalLogDecoration;
    }

    public DetailLogDecoration logDetail() {
        final DetailLogDecoration detailLogDecoration = new DetailLogDecoration();
        this.logDecoration = detailLogDecoration;
        return detailLogDecoration;
    }

    public BoxLogDecoration logBox() {
        final BoxLogDecoration boxLogDecoration = new BoxLogDecoration();
        this.logDecoration = boxLogDecoration;
        return boxLogDecoration;
    }

    /**
     * 设置为自定义的日志内容装饰器
     *
     * @param logDecoration
     * @return
     */
    public Settings logDecoration(LogDecoration logDecoration) {
        this.logDecoration = logDecoration;
        return this;
    }

    /**
     * 为指定的日志级别设置装饰器
     *
     * @param logLevel
     * @param logDecoration
     * @return
     */
    public Settings logDecoration(int logLevel, LogDecoration logDecoration) {
        if (mLogDecorationMap == null) {
            mLogDecorationMap = new HashMap<>();
        }
        mLogDecorationMap.put(logLevel, logDecoration);
        return this;
    }

    LogDecoration getLogDecoration(int logLevel) {
        if (mLogDecorationMap != null) { //有配置则使用map中的配置
            LogDecoration decoration = mLogDecorationMap.get(logLevel);
            if (decoration != null) {
                return decoration;
            }
        }
        if (this.logDecoration == null && proxy != null) {
            return proxy.getLogDecoration(logLevel);
        }
        return logDecoration;
    }

    /*--------------------------------LogDecoration配置---END-----------------------------*/


    /*--------------------------------PipeLine配置---START-----------------------------*/

    /**
     * 开启日志存储,开启以后,可以通过链式API进行文件存储的相关配置.文件存储用默认的地址
     *
     * @param level  日志级别
     * @param logDir
     * @return
     */
    public FilePipeLine openLogSave(int level, String logDir) {
        if (filePipeLine == null) {
            filePipeLine = FilePipeLine.pipeLine(logDir);
        }
        addPipeLine(filePipeLine.level(level));
        return filePipeLine;
    }

    /**
     * @param ctx   主要是为了获取默认的存储路径
     * @param level
     * @return
     * @see #openLogSave(int, String)
     */
    public FilePipeLine openLogSave(Context ctx, int level) {
        final String logDir = FilePipeLine.logDir(ctx, "logs");
        return openLogSave(level, logDir);
    }

    public FilePipeLine openLogSave(Context ctx) {
        return openLogSave(ctx, Log.ERROR);
    }

    FilePipeLine openLogSave() {
        return openLogSave(null);
    }

    /**
     * 关闭日志存储
     *
     * @return
     */
    public Settings closeLogSave() {
        removePipeLine(filePipeLine);
        return this;
    }

    public Settings removePipeLine(FilePipeLine filePipeLine) {
        if (pipeLineList == null) {
            pipeLineList = new ArrayList<>();
        }
        pipeLineList.remove(filePipeLine);
        return this;
    }

    public Settings addPipeLine(PipeLine pipeLine) {
        if (pipeLineList == null) {
            pipeLineList = new ArrayList<>();
        }
        if (!pipeLineList.contains(pipeLine)) {
            pipeLineList.add(pipeLine);
        }
        return this;
    }
    /*--------------------------------PipeLine配置---END-------------------------------*/


    /**
     * 执行所有的pipeline
     *
     * @param logType
     * @param finalTag
     * @param finalMsg
     */
    void runPipelines(int logType, String finalTag, String[] finalMsg, Throwable t) {
        List<PipeLine> pipeLineList = this.pipeLineList == null && proxy != null ? proxy.pipeLineList : this.pipeLineList;
        if (finalMsg != null && finalMsg.length > 0) {
            for (int i = 0; i < pipeLineList.size(); i++) {
                synchronized (this) { //保证同一条日志的打印顺序
                    for (int j = 0; j < finalMsg.length; j++) {
                        pipeLineList.get(i).pipeline(logType, finalTag, finalMsg[j], t);
                    }
                }
            }
        }
    }
}
